package screen;

import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;

import keyboard.KeyCode;
import state.State;
import utils.ArraysUtil;
import utils.Screen;
import book.Book;
import book.PageManager;
import book.PhraseFader;
import book.PhraseFaderImpl;

public class BookScreen extends Canvas implements Repaintable, CommandListener {

	private static int INNER_SCREEN_WIDTH = Screen.SCREEN_WIDTH - Screen.SIDE_MARGIN * 2;
	// font height = 26
	private final Command pageOK = new Command("OK", Command.OK, 1);
	private final Command pageDelete = new Command("Delete", Command.CANCEL, 1);

	private PageManager pageManager;

	private boolean alreadySetup = false;
	private int numLineOnScreen;
	private Graphics g;
	private PhraseFader phraseFader;
	int lineIndex = 0;
	private String phrase;
	private boolean isNewPhrase = false;
	private String[] phraseChunks;
	private Book book;
	private boolean isShowSpeed = false;
	private boolean isFirstNumeral = true;

	public BookScreen(Book aBook) {
		book = aBook;
		phraseFader = new PhraseFaderImpl(this);
		pageManager = new PageManager();
		setCommandListener(this);
	}

	protected void paint(Graphics someg) {
		g = someg;
		if (!alreadySetup) {
			setup();
		}
		if (phrase == null) {
			return;
		}
		try {
			if (phraseFader.isFadeInprogress()) {
				if (isNewPhrase) {
					phraseFader.blackRepaint(g);
				} else {
					phraseFader.repaint(g);
				}
			}
			if (isNewPhrase) {
				splitPhrase();
				if ((lineIndex + phraseChunks.length) <= numLineOnScreen) {
					writePhraseFomIndix();
				} else {
					eraseSlate();
					lineIndex = 0;
					writePhraseFomIndix();
				}
				lineIndex = lineIndex + phraseChunks.length;
				isNewPhrase = false;
			} else {
				// We do nothing
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			String message = "";
			for (int i = 0; i < phraseChunks.length; i++) {
				message += phraseChunks[i] + "\n";
			}
			Book.debugAlert("BUG\nisNewPhrase = " + isNewPhrase
					+ "\nPhrase chunks:\n" + message);
		}
		deleteMessage();

		if (isShowSpeed) {
			int speed = book.getSpeed();
			String text = "Speed = " + speed;
			showMessage(text);

		} else if (Book.getState().equals(State.IN_PAUSE)) {

			String text = "Pause";
			g.setColor(Colors.GREY);
			showMessage(text);
		}

		if (Book.getState().equals(State.PAGE_SELECTION)) {
			drawPageSelectionField();
		}
	}

	private void showMessage(String text) {
		g.setColor(Colors.GREY);
		g.drawString(text, Screen.SCREEN_WIDTH / 2, g.getFont().getHeight() / 2,
				Graphics.TOP | Graphics.HCENTER);
	}

	private void drawPageSelectionField() {
		int pageNumber = pageManager.getPage();
		String value = Integer.toString(pageNumber);
		if (pageNumber == PageManager.NO_PAGE) {
			value = "";
		}
		String text = "Page = " + value;
		showMessage(text);
	}

	private void deleteMessage() {
		g.setColor(Colors.BLACK);
		g.fillRect(0, 0, Screen.SCREEN_WIDTH, g.getFont().getHeight() * 2);
	}

	private void writePhraseFomIndix() {
		phraseFader.setupFading(phraseChunks, lineIndex, PhraseFader.UPWARDS);
		phraseFader.repaint(g);

	}

	private void eraseSlate() {
		int previousColor = g.getColor();
		g.setColor(Colors.BLACK);
		g.fillRect(0, 0, Screen.SCREEN_WIDTH, Screen.SCREEN_HEIGHT);
		g.setColor(Colors.WHITE);
		g.fillRect(0, Screen.BLACK_TOP_HEIGHT, Screen.SCREEN_WIDTH, Screen.SIDE_MARGIN * 3
				+ g.getFont().getHeight() * 6);
//		g.fillRoundRect(0, BLACK_TOP_HEIGHT, SCREEN_WIDTH, SIDE_MARGIN * 3
//				+ g.getFont().getHeight() * 6, 10, 10);
		// g.fillRect(0, SIDE_MARGIN + g.getFont().getHeight()*6, SCREEN_WIDTH,
		// SCREEN_HEIGHT);
		g.setColor(previousColor);
	}
	
	private void splitPhrase() {

		phraseChunks = new String[300];
		String phraseEnd = phrase;
		int index = 0;

		while (getWidth(phraseEnd) > INNER_SCREEN_WIDTH) {
			String chunk = null;
			boolean isChunkDone = false;

			while (!isChunkDone) {
				int blankIndex = phraseEnd.indexOf(" ");

				if (blankIndex < 0) {
					isChunkDone = true;
				} else {
					String candidateChunk;

					if (chunk == null) {
						candidateChunk = phraseEnd.substring(0, blankIndex);
					} else {
						candidateChunk = chunk + " "
								+ phraseEnd.substring(0, blankIndex);
					}
					if (getWidth(candidateChunk) < INNER_SCREEN_WIDTH) {
						chunk = candidateChunk;
						phraseEnd = phraseEnd.substring(blankIndex + 1);
					} else {
						if (chunk == null) {
							// The first word is longer than screen width
							chunk = candidateChunk;
							phraseEnd = phraseEnd.substring(blankIndex + 1);
						}
						isChunkDone = true;
					}
				}

			}
			phraseChunks[index++] = chunk;
		}
		phraseChunks[index++] = phraseEnd;
		phraseChunks = ArraysUtil.compact(phraseChunks, index);
		// try {
		// } catch (ArrayIndexOutOfBoundsException e) {
		// Book.debugAlert("found\nisNewPhrase = " + isNewPhrase + "\nGuilty = "
		// + guilty);
		// }
	}

	private int getWidth(String phraseEnd) {
		return g.getFont().stringWidth(phraseEnd);
	}

	private void setup() {
		numLineOnScreen = 6;
		eraseSlate();
		alreadySetup = true;
	}

	public void displayPhrase(String aPhrase) {
		phrase = aPhrase.trim();
		isNewPhrase = true;
		repaint();
	}

	public void keyPressed(int keyCode) {
		if (!Book.getState().equals(State.PAGE_SELECTION)) {
			if (keyCode == KeyCode.ASTERISK) {
				book.eventDestroy();
			} else if (keyCode == KeyCode.BAS) {
				book.eventDownPressed();
			} else if (keyCode == KeyCode.GAUCHE) {
				book.eventLeftPressed();
			} else if (keyCode == KeyCode.DROITE) {
				book.eventRightPressed();
			} else if (keyCode == KeyCode.ONE) {
				book.eventOnePressed();
			} else if (keyCode == KeyCode.FOUR) {
				book.eventFourPressed();
			} else if (keyCode == KeyCode.TWO) {
				book.buttonPausePushed();
			} else if (keyCode == KeyCode.FIVE) {
				book.eventFivePressed();
			}
		} else if ((keyCode >= 48) && (keyCode <= 57)) {
			int numeral = keyCode - 48;
			if (isFirstNumeral) {
				pageManager.setPage(numeral);
				repaint();
				isFirstNumeral = false;
			} else {				
				pageManager.newNumeralEntered(numeral);
				repaint();
			}
		}
			
			
	}

	public void showSpeed() {
		isShowSpeed = true;
		repaint();
		new Timer().schedule(new TimerTask() {

			public void run() {
				isShowSpeed = false;
				repaint();
			}
		}, 1000);
	}

	public void computePage(int phraseIndex) {
		pageManager.computePage(phraseIndex);
	}

	public void computeCommands() {
		if (Book.getState().equals(State.PAGE_SELECTION)) {
			addCommand(pageOK);
			addCommand(pageDelete);
		} else {
			removeCommand(pageOK);
			removeCommand(pageDelete);
		}
	}

	public void commandAction(Command command, Displayable arg1) {
		if (command == pageOK) {
			Book.getState().remove(State.PAGE_SELECTION);
			computeCommands();
			repaint();

			if (isFirstNumeral) {
				book.eventBackToReading();
			} else {
				int phraseIndex = pageManager.getPhraseIndex();
				book.eventNewPhraseIndexSelected(phraseIndex);				
				isFirstNumeral  = true;
			}
		} else if (command == pageDelete) {
			pageManager.deletePageUnities();
			repaint();
		}
	}
}
